#region Using References

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

#endregion

namespace Beaker.Services.FileSystem.Physical
{
	public sealed class FileSystemService
		: FolderBase, IFileSystemService
	{
		public FileSystemService()
			: base( null )
		{
		}

		/// <summary>
		/// Gets the name of the entry
		/// </summary>
		public override string Name
		{
			get { return null; }
		}

		/// <summary>
		/// Gets the file with the given name.
		/// </summary>
		/// <param name="fileName">The name of the file to get.</param>
		/// <returns>The file with the given name, or <c>null</c> when it could not be found.</returns>
		public override IFile GetFile( string fileName )
		{
			return null;
		}

		/// <summary>
		/// Gets the folder with the given name.
		/// </summary>
		/// <param name="folderName">The name of the folder to get.</param>
		/// <returns>The folder with the given name, or <c>null</c> when it could not be found.</returns>
		public override IFolder GetFolder( string folderName )
		{
			DriveInfo driveInfo =
				DriveInfo.GetDrives()
					.FirstOrDefault(di => di.Name.Equals( folderName, StringComparison.InvariantCultureIgnoreCase ));

			if( driveInfo == null )
				return null;

			return new DriveFolder( this, driveInfo );
		}

		/// <summary>
		/// Gets the entires in this folder.
		/// </summary>
		/// <returns>
		/// A sequence of items.
		/// </returns>
		public override IEnumerable<IFileSystemEntry> GetEntries()
		{
			return
				DriveInfo.GetDrives()
					.Select( d => new DriveFolder( this, d ) );
		}

		/// <summary>
		/// Gets the entry with the given name in this folder.
		/// </summary>
		/// <param name="entryName">Name of the entry to get.</param>
		/// <returns>The entry with the given name, or <c>null</c> when it could not be found.</returns>
		public override IFileSystemEntry GetEntry( string entryName )
		{
			return GetFolder( entryName );
		}

		/// <summary>
		/// Parse the given path and return a file or folder for it
		/// </summary>
		/// <param name="path">The path to parse</param>
		/// <returns>
		/// A IFileSystemEntry with the file or folder, or <c>null</c> when the file or folder does not exist
		/// </returns>
		/// <exception cref="System.IO.DirectoryNotFoundException">Thrown when some part of the part does not exist.</exception>
		/// <exception cref="FormatException">Thrown when the path could not be parsed.</exception>
		public IFileSystemEntry ParsePath( string path )
		{
			// first we make the path absolute
			string fullPath = Path.GetFullPath( path );
			IFolder folder = this;

			// the we split it up in segments
			string[] segments = path.Split( new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar } );
			if( segments[0] != null )
				segments[0] += @"\";

			// now keep using get entry
			IFileSystemEntry entry = null;
			foreach( string entryName in segments )
			{
				if( folder == null )
					throw new DirectoryNotFoundException();

				entry = folder.GetEntry( entryName );
				folder = entry as IFolder;
			}

			return entry;
		}

		/// <summary>
		/// Gets the requested special folder
		/// </summary>
		/// <param name="folder">The special folder to get</param>
		/// <returns>The requested special folder</returns>
		public IFolder GetSpecialFolder( Environment.SpecialFolder folder )
		{
			return ParsePath( Environment.GetFolderPath( folder ) ) as IFolder;
		}
	}
}